﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Luna;
using System.Text.RegularExpressions;

namespace TextDataExtractor.DEML {
	public abstract class AbstractAction : DemlElement {

		public static readonly Regex FormatPlaceholder = new Regex(@"\{([^\[]*)(\[(.+?)\])?(:(.+))?\}", RegexOptions.Multiline);
		public static readonly Regex VarName = new Regex(@"(\$[^\[]*)(\[(.+?)\])?", RegexOptions.Multiline);
		public static readonly Regex IdParser = new Regex(@"([^\.]*)\.?", RegexOptions.Multiline);

		public IEnumerable<IDataFilter> Filters {
			get {
				return getChildren<IDataFilter>();
			}
		}

		public virtual void execute(ExecutionContext context) {
			
		}

		protected virtual IDataProvider resolveVariableName(ExecutionContext context, string identifier, out string indexer) {
			Match m = IdParser.Match(identifier);
			IDataProvider var = null; indexer = string.Empty;
			while (m.Success) {
				if (m.Groups[1].Value.isNotNullAndEmpty()) {
					if (var == null)
						var = context.getVariable(m.Groups[1].Value);
					else {
						if (indexer.isNotNullAndEmpty())
							var = var.getDataItem(indexer) as IDataProvider;
						indexer = m.Groups[1].Value;
					}
					if (var == null)
						break;
					m = m.NextMatch();
				}
				else break;
			}
			return var;
		}

		protected virtual object getValue(ExecutionContext context, string ns, string index) {
			object result = null;
			IDataProvider storage = null;
			string indexer = null;

			if (string.IsNullOrWhiteSpace(ns))
				storage = (IDataProvider)context.ActivePattern;
			else if (ns.StartsWith("$")) {
				
				storage = resolveVariableName(context, ns, out indexer);
				if (storage != null && indexer.isNotNullAndEmpty())
					if (index.isNotNullAndEmpty())
						storage = (IDataStorage)storage.getDataItem(indexer);
					else
						index = indexer;
			}
			else
				storage = (IDataProvider)context[ns];
			
			if (storage != null)
				result = storage.getDataItem(index);
			return result;
		}

		protected virtual object formatValue(ExecutionContext context, string template) {
			List<object> args = new List<object>();
			string ires = template;
			object result = null;
			if (template.StartsWith("$")) {
				Match m = VarName.Match(template);
				if (m.Success) {
					string varname = m.Groups[1].Value;
					string index = m.Groups[3].Value;
					result = getValue(context, varname, index);
				}
			}
			else {
				Match m = FormatPlaceholder.Match(template);
				while (m.Success) {
					string varname = m.Groups[1].Value;
					string index = m.Groups[3].Value;
					string format = m.Groups[5].Value;

					ires = ires.Replace(m.Value, string.Format("{0" + format + "}", getValue(context, varname, index)));
					m = m.NextMatch();
				}
				result = ires;
			}
			foreach (IDataFilter filter in Filters)
				result = filter.applyFilter(context, result);
			return result;
		}

		protected override void processChildNode(System.Xml.XmlNode child, DemlRegistry registry) {
			if (child.Name.Equals("filter")) {
				string name = child.getAttribute("name");
				IDataFilter filter = (IDataFilter)DemlFactory.Instance.createElement(ElementType.DataFilter, name);
				if (filter != null) {
					filter.loadFromXml(child, registry);
					this.Children.Add(filter);
				}
			}
			else if (DemlFactory.Instance.isElementType(ElementType.DataFilter, child.Name)) {
				IDataFilter filter = (IDataFilter)DemlFactory.Instance.createElement(ElementType.DataFilter, child.Name);
				if (filter != null) {
					filter.loadFromXml(child, registry);
					this.Children.Add(filter);
				}
			}
		}

		public override DemlElement Clone() {
			return this;
		}
	}
}
